/*
  project:esp32-epd213
  using DEPG0213RH EDP


*/
#include "Config.h"





int modeButtonState = HIGH, modeButtonState_t = HIGH;
int keepButtonState = HIGH;
int modeButtonCount = 0;  //mode按键计数

int setButtonState = HIGH, setButtonState_t = HIGH;
int setButtonCount = 0;  //mode按键计数


enum { FUNC_CLOCK,
       FUNC_TCLOCK,
       FUNC_WIFICFG };

int functionmode = FUNC_CLOCK;  //显示模式

boolean changingMode = true;  //模式是否改变
boolean keepingMode = true;   //是否保持当前状态

int configOption = 0;        //设置选项
boolean configMode = false;  //是否处在设置模式下
boolean firstFlag = true;
boolean updateDraw = false;
boolean isconnecting = false;  //是否在配网
boolean settingMode = true;    //配网是否成功

int ticount_0 = 0;  //模式0计数
int ticount_1 = 0;  //模式1计数
int ticount_2 = 0;  //模式2计数

int tclockCountFlag = 0;

String ip;
DNSServer dnsServer;  //服务器对象


//dht11


void setup() {
  // put your setup code here, to run once:
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  pinMode(modePin, INPUT_PULLUP);  //按键设为输入模式,内部上拉
  pinMode(setPin, INPUT_PULLUP);

  pinMode(usbCheckPin, INPUT_PULLDOWN);
  pinMode(chargeStatePin, INPUT);

  pinMode(ctrlPowerPin, OUTPUT);
  pinMode(keyInPin, INPUT_PULLUP);


  Serial.begin(115200);
  Serial.println();
  Serial.println("project:esp32-epd213 v1.0");
  Serial.printf("compile date:%s\n", __DATE__);
  EEPROM.begin(4096);
  Serial.println("app start.");
 usbCheckState = digitalRead(usbCheckPin);
  Serial.print("usb:");
  Serial.println(usbCheckState);
  Serial.print("usb pin analoge:");
  Serial.println(analogRead(usbCheckPin));
  Serial.print("usb state:");
  Serial.println( usbCheckState ? "pulged" : "unplug");
  chargeState = !digitalRead(chargeStatePin);
  Serial.printf("charge state:%s.\n", chargeState ? "charged" : "uncharge");

  //power io control when ussing lipot
  //if(!usbCheckState)
  {
    //check   keyInPin 
    if(digitalRead(keyInPin) == LOW)
    {
      int startModeKeyTime = millis();

      delay(500);
      while(digitalRead(keyInPin) == LOW)
      {
        //set power io on
        Serial.println("mode btn press on start.");

        if(millis() - startModeKeyTime >8000 )
        {
          //led on
          Serial.println("open led.");
          digitalWrite(ledPin, HIGH);
          delay(100);
          Serial.println("power enable.");
          digitalWrite(ctrlPowerPin,HIGH);
          Serial.println("set power io on.");
          delay(5000);
          break;
        }
        
      }
       Serial.println("close led.");
       digitalWrite(ledPin, LOW);
    }  
  }/*
  else{

    Serial.println("usb mode,power by usb.");

  }
*/
  adc1_config_width(ADC_WIDTH);
  adc1_config_channel_atten(ADC1_CHANNEL_5,ADC_ATTEN);
  adc_charts = (esp_adc_cal_characteristics_t * ) malloc(sizeof(esp_adc_cal_characteristics_t));
  esp_adc_cal_value_t val_type = esp_adc_cal_characterize(ADC_UNIT_1,ADC_ATTEN,ADC_WIDTH,DEFAULT_VREF,adc_charts);

  Serial.println("Dht11 ini.");
  dht.begin();

  hspi.begin(13, 12, 14, 15);  // remap hspi for EPD (swap pins)
  display.epd2.selectSPI(hspi, SPISettings(4000000, MSBFIRST, SPI_MODE0));
  display.init(115200);
  u8g2Fonts.begin(display);  //将u8g2连接到display
  display.setRotation(1);    //设置屏幕方向为竖屏
  display.firstPage();
  //display.display(1);
  startDhtTime = millis();
  Tem = dht.readTemperature();
  Hum = dht.readHumidity();
  ticount_0=millis();
  ticount_1=millis();
#if 0
  showStart();
  delay(1000);
#endif

#if 0
  showNihao();
  delay(1000);
#endif

#if 0
  showImg();
  delay(1000);

#endif

#if 0
  Serial.println("Step:sleep.");
  display.powerOff();
  deepSleepTest();
  display.end();
#endif
  Serial.println("setup done");
  display_wificonfig_page();
}

void loop() {
  // put your main code here, to run repeatedly:
    if ((millis() - startDhtTime > updateDhtTime) || millis()< 50000) {
    Serial.println("read dht.");
    Tem = dht.readTemperature();
    Hum = dht.readHumidity();
    startDhtTime = millis();
    Serial.print(F("Humidity: "));
    Serial.print(Hum);
    Serial.print(F("%  Temperature: "));
    Serial.print(Tem);
    Serial.print(F("°C "));


    int val1= adc1_get_raw((adc1_channel_t)5);
    int voltage1 = esp_adc_cal_raw_to_voltage(val1, adc_charts)*2.0;
    //Serial.printf("analog a5 pin 33 val:%d\n",val1);
    //Serial.printf("a5 Raw: %d\tVoltage: %dmV\n", val1, voltage1);
    Serial.printf("A5(IO33) Raw: %d\tVoltage: %dmV\n", val1, voltage1);
    int powerCap = 100*(voltage1 -(3700))/(4200-3700);
    if(powerCap<0)powerCap=0;
    if(powerCap>100)powerCap=100;
    Serial.printf("power cap:%d%%",powerCap);
    
  }


  //显示模式
  if (!configMode) {
    switch (functionmode) {
        //时钟
      case FUNC_CLOCK:
        // Serial.printf("display mode.\n");
        if (changingMode) {
          display.fillScreen(GxEPD_WHITE);
          //display.drawInvertedBitmap(0, 0, date_pic, 128, 296, GxEPD_BLACK);
          u8g2Fonts.setFontMode(1);       // use u8g2 transparent mode (this is default)
          u8g2Fonts.setFontDirection(0);  // left to right (this is default)
          u8g2Fonts.setFont(chinese_city_gb2312);
          u8g2Fonts.setForegroundColor(GxEPD_BLACK);  // 设置前景色
          u8g2Fonts.setBackgroundColor(GxEPD_WHITE);  // 设置背景色
          u8g2Fonts.setCursor(160, 18);
          u8g2Fonts.print("时钟页");
          u8g2Fonts.setCursor(160, 36);
          u8g2Fonts.print("联网");
          display.nextPage();
          changingMode = false;
        }
        //if (settingMode && !keepingMode) display_wificonfig_page();
        //if (!settingMode && (ticount_0 == flashtime_0 || !keepingMode))

        if (!settingMode && (millis() - ticount_0 > flashtime_0 || firstFlag)) {
          Serial.println("ini NTP.");
          initNTP();            // NTP获取时间
          TimeChangeRule *tcr;  // Pointer to the time change rule
          time_t utc = now();
          TimeChangeRule mySTD = { "", First, Sun, Jan, 0, timezone_offset * 60 };  //东八区
          Timezone myTZ(mySTD, mySTD);
          time_t localTime = myTZ.toLocal(utc, &tcr);
          
          if (changingMode || minute(localTime) == 0 ||firstFlag)  //按下KEEP或MODE键或分钟为0或完成配网是全屏刷新屏幕
          {
            firstFlag = false;
            changingMode = false;
            display.setFullWindow();
            display.fillScreen(GxEPD_WHITE);
            display.drawLine(0, 18, 212, 18, GxEPD_BLACK);

            display.drawInvertedBitmap(0, 0, gImage_clock, 18, 18, GxEPD_BLACK);
            display_dinosaur_time_page();
            display.nextPage();
          } else {
            uint16_t box_x = 0;
            uint16_t box_y = 18;
            uint16_t box_w = 212;
            uint16_t box_h = 102;
            display.setPartialWindow(box_x, box_y, box_w, box_h);  //仅局部刷新时间
            display.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE);
            display_dinosaur_time_page();
            display.nextPage();
          }
        }

        if (millis() - ticount_0 > flashtime_0) ticount_0 = millis();
        //ticount_0++;
        delay(10);
        break;
      //番茄钟tomato clock
      case FUNC_TCLOCK:

        if (!settingMode && ( millis() - ticount_1 > flashtime_1 || firstFlag || updateDraw) )
         {
            
            if (changingMode || tclockMinutesLast % 5 == 0||firstFlag || updateDraw)  //按下KEEP或MODE键或分钟为0或完成配网是全屏刷新屏幕
            {
              firstFlag = false;
              updateDraw = false;
              display.setFullWindow();
              display.fillScreen(GxEPD_WHITE);
              display.drawLine(0, 18, 212, 18, GxEPD_BLACK);
              display.drawInvertedBitmap(20, 0, gImage_tclock, 18, 18, GxEPD_BLACK);
              display_tclock_time_page();
              display.nextPage();
            } else {
              uint16_t box_x = 0;
              uint16_t box_y = 18;
              uint16_t box_w = 212;
              uint16_t box_h = 102;
              display.setPartialWindow(box_x, box_y, box_w, box_h);  //仅局部刷新时间
              display.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE);
              display_tclock_time_page();
              display.nextPage();
            }
        }
        if (millis() - ticount_1 > flashtime_1 ) ticount_1 = millis();
        //ticount_1++;
        delay(10);

        break;
      //wifi config.
      case 2:

        break;
      case 3:


        break;
      default:
        break;
    }
  } else {
    //设置模式
    if (changingMode) {
      display.fillScreen(GxEPD_WHITE);
      //display.drawInvertedBitmap(0, 0, date_pic, 128, 296, GxEPD_BLACK);
      u8g2Fonts.setFontMode(1);       // use u8g2 transparent mode (this is default)
      u8g2Fonts.setFontDirection(0);  // left to right (this is default)
      u8g2Fonts.setFont(chinese_city_gb2312);
      u8g2Fonts.setForegroundColor(GxEPD_BLACK);  // 设置前景色
      u8g2Fonts.setBackgroundColor(GxEPD_WHITE);  // 设置背景色
      u8g2Fonts.setFont(chinese_city_gb2312);
      u8g2Fonts.setCursor(160, 18);
      u8g2Fonts.print("配置页");
      display.nextPage();
      changingMode = false;
    }
  }

  Serial.print(".");

  //btn control
  modeButtonState = digitalRead(modePin);  //按键

  if (modeButtonState == LOW) {
    if (modeButtonCount < 40) digitalWrite(ledPin, HIGH);  //on
    else digitalWrite(ledPin, LOW);
    modeButtonState_t = LOW;
    modeButtonCount++;
    delay(50);
    Serial.println("mode按下 ");
  } else {
    digitalWrite(ledPin, LOW);

    if (modeButtonState_t == LOW) {
      Serial.println("mode松开 ");
      // webServer.close();
      if (modeButtonCount < 40) {
        if (!configMode) {
          Serial.println("显示模式下MODE短按 ");
          //pasue tomato clock

          if (functionmode == 1)
            functionmode = 0;
          else
            functionmode++;

          display.setFullWindow();
          Serial.print("MODE短按,切换功能模块,functionmode=");
          Serial.println(functionmode);

          changingMode = true;
          firstFlag = true;
        } else {
          /*设置模式下短按mode键*/
          Serial.println("设置模式下MODE短按 ");
          //change clock time
          /*
                    configOption++;
                    if(configOption==2) configOption=0;
                    firstFlag = true;     
                    */
        }
      } else {
        Serial.println("MODE长按 ");

        changingMode = true;
        configMode = !configMode;
        firstFlag = true;

        display.setFullWindow();
      }
    }
    if (modeButtonState != modeButtonState_t) {
      Serial.println("mode btn state change. ");
      Serial.printf("modeButtonCount:%d\n", modeButtonCount);
    }
    modeButtonCount = 0;
    modeButtonState_t = HIGH;
  }

  //set btn control
  //btn control
  setButtonState = digitalRead(setPin);  //按键
  if (setButtonState == LOW) {

    setButtonState_t = LOW;
    setButtonCount++;
    delay(50);
  } else {
    if (setButtonState_t == LOW) {
      if (setButtonCount > 40) {
        Serial.println("set长按 ");
        if (functionmode == FUNC_TCLOCK) {
          //start
          if (tamatoClockState == CLOCK_PAUSE) {
            Serial.printf("set tamato clock default.");
            tamatoClockState == CLOCK_STOP;
          }
        }

      } else {  //短按

        if (functionmode == FUNC_TCLOCK) {
          Serial.println("set短按,切换Tclock mode. ");

          //start
          if (tamatoClockState == CLOCK_STOP) {
            Serial.printf("start tamato clock.");
            
            firstFlag = true;
            tclockCountFlag = true;
            tmpTclockMinutes =0;
            tamatoClockState = CLOCK_RUNNING;
          } else if (tamatoClockState == CLOCK_RUNNING) {
            Serial.printf("tamato clock pause.");
            tamatoClockState = CLOCK_PAUSE;
            changingMode = true;
          } else if (tamatoClockState == CLOCK_PAUSE) {
            Serial.printf("tamato clock running.");
            changingMode = true;
            tamatoClockState = CLOCK_RUNNING;
          } else if (tamatoClockState == CLOCK_TIMEOVER) {
            Serial.printf("tamato clock stop.");
            startTclockMinutes = 0;
            tclockMinutesLast = defaultTclockMinutes;
            tamatoClockState = CLOCK_STOP;
          }
          Serial.printf("Tclock mode:%d\n ", tamatoClockState);
          updateDraw = true;
        }

      }
    }
    setButtonCount = 0;
    setButtonState_t = HIGH;
  }
}

void showStart() {
  Serial.println("show start.");
  Serial.print("start time:");
  Serial.println(millis());
  u8g2Fonts.setFontMode(1);                   // use u8g2 transparent mode (this is default)
  u8g2Fonts.setFontDirection(0);              // left to right (this is default)
  u8g2Fonts.setForegroundColor(GxEPD_BLACK);  // 设置前景色
  u8g2Fonts.setBackgroundColor(GxEPD_WHITE);  // 设置背景色
  u8g2Fonts.setFont(u8g2_font_helvR14_tf);    // select u8g2 font from here: https://github.com/olikraus/u8g2/wiki/fntlistall

  display.firstPage();
  do {
    display.fillScreen(GxEPD_WHITE);
    u8g2Fonts.setCursor(0, 16);
    u8g2Fonts.print("start");
  } while (display.nextPage());
  Serial.println("show start complete.");
  Serial.print("end time:");
  Serial.println(millis());
}


void showNihao() {
  Serial.println("show hello.");
  u8g2Fonts.setFontMode(1);                   // use u8g2 transparent mode (this is default)
  u8g2Fonts.setFontDirection(0);              // left to right (this is default)
  u8g2Fonts.setForegroundColor(GxEPD_BLACK);  // 设置前景色
  u8g2Fonts.setBackgroundColor(GxEPD_WHITE);  // 设置背景色
  u8g2Fonts.setFont(chinese_city_gb2312);     // select u8g2 font from here: https://github.com/olikraus/u8g2/wiki/fntlistall

  display.firstPage();
  do {
    //display.fillScreen(GxEPD_WHITE);
    u8g2Fonts.setCursor(0, 32);
    u8g2Fonts.print("你好,中国！");
  } while (display.nextPage());
}

void showImg() {
  display.firstPage();
  do {
    //display.fillScreen(GxEPD_WHITE);
    Serial.println("show img1.");
    display.drawInvertedBitmap(0, 0, girl1, display.width(), display.height(), GxEPD_BLACK);
  } while (display.nextPage());
  delay(1000);
  display.firstPage();
  do {
    //display.fillScreen(GxEPD_WHITE);
    Serial.println("show img2.");
    display.drawInvertedBitmap(0, 0, shan, display.width(), display.height(), GxEPD_BLACK);
  } while (display.nextPage());

  delay(1000);

  display.firstPage();
  do {
    //display.fillScreen(GxEPD_WHITE);
    Serial.println("show img3.");
    display.drawInvertedBitmap(0, 0, tongtong, display.width(), display.height(), GxEPD_BLACK);
  } while (display.nextPage());
}

void deepSleepTest() {
  //Serial.println("deepSleepTest");
  const char hibernating[] = "hibernating ...";
  const char wokeup[] = "woke up";
  const char from[] = "from deep sleep";
  const char again[] = "again";
  display.setRotation(1);
  display.setFont(&FreeMonoBold9pt7b);
  if (display.epd2.WIDTH < 104) display.setFont(0);
  display.setTextColor(GxEPD_BLACK);
  int16_t tbx, tby;
  uint16_t tbw, tbh;
  // center text
  display.getTextBounds(hibernating, 0, 0, &tbx, &tby, &tbw, &tbh);
  uint16_t x = ((display.width() - tbw) / 2) - tbx;
  uint16_t y = ((display.height() - tbh) / 2) - tby;
  display.setFullWindow();
  display.firstPage();
  do {
    display.fillScreen(GxEPD_WHITE);
    display.setCursor(x, y);
    display.print(hibernating);
  } while (display.nextPage());
  display.hibernate();
  delay(5000);
  display.getTextBounds(wokeup, 0, 0, &tbx, &tby, &tbw, &tbh);
  uint16_t wx = (display.width() - tbw) / 2;
  uint16_t wy = ((display.height() / 3) - tbh / 2) - tby;  // y is base line!
  display.getTextBounds(from, 0, 0, &tbx, &tby, &tbw, &tbh);
  uint16_t fx = (display.width() - tbw) / 2;
  uint16_t fy = ((display.height() * 2 / 3) - tbh / 2) - tby;  // y is base line!
  display.firstPage();
  do {
    display.fillScreen(GxEPD_WHITE);
    display.setCursor(wx, wy);
    display.print(wokeup);
    display.setCursor(fx, fy);
    display.print(from);
  } while (display.nextPage());
  delay(5000);
  display.getTextBounds(hibernating, 0, 0, &tbx, &tby, &tbw, &tbh);
  uint16_t hx = (display.width() - tbw) / 2;
  uint16_t hy = ((display.height() / 3) - tbh / 2) - tby;  // y is base line!
  display.getTextBounds(again, 0, 0, &tbx, &tby, &tbw, &tbh);
  uint16_t ax = (display.width() - tbw) / 2;
  uint16_t ay = ((display.height() * 2 / 3) - tbh / 2) - tby;  // y is base line!
  display.firstPage();
  do {
    display.fillScreen(GxEPD_WHITE);
    display.setCursor(hx, hy);
    display.print(hibernating);
    display.setCursor(ax, ay);
    display.print(again);
  } while (display.nextPage());
  display.hibernate();
  //Serial.println("deepSleepTest done");
}
